/*
 * Copyright (c) 2017-2021, Lindenis Tech. Ltd.
 * All rights reserved.
 *
 * File:
 *
 * Description: reliable data transfer
 *
 * Author:
 *      xiaoshujun@lindeni.com
 *
 * Create Date:
 *      2021/03/09
 *
 * History:
 *
 */

#ifndef __LIND_NETWORK_H__
#define __LIND_NETWORK_H__

#ifdef __cplusplus
extern "C" {
#endif

#ifdef WIN32
#include <winsock2.h>
#include <ws2tcpip.h>
#else
#ifndef MELIS_OS
#include <netinet/in.h>
#endif  // MELIS_OS
#endif  // WIN32
#include "osal_types.h"

#define MAX_MTU                     1500

#define IP_HEAD_SIZE                20
#define UDP_HEAD_SIZE               8
#define TCP_HEAD_SIZE               20
#define RDT_HEAD_SIZE               24
#define RTP_HEAD_SIZE               12

#define udp_payload_size(mtu)           (mtu - IP_HEAD_SIZE - UDP_HEAD_SIZE)
#define tcp_payload_size(mtu)           (mtu - IP_HEAD_SIZE - TCP_HEAD_SIZE)
#define rtp_payload_size_base_udp(mtu)  ((udp_payload_size(mtu)) - RTP_HEAD_SIZE)
#define rtp_payload_size_base_tcp(mtu)  ((tcp_payload_size(mtu)) - RTP_HEAD_SIZE)
#define rdt_payload_size_base_udp(mtu)  ((udp_payload_size(mtu)) - RDT_HEAD_SIZE)
#define rtp_payload_size_base_rdt(mtu)  ((rdt_payload_size_base_udp(mtu)) - RTP_HEAD_SIZE)

typedef enum _lindnet_type_e
{
    LINDNET_TYPE_UDP = 0,
    LINDNET_TYPE_TCP,
    LINDNET_TYPE_RDT,
} lindnet_type_e;

typedef enum _lindnet_msg_e
{
    LINDNET_MSG_SESSION_CONNECT     = 0,
    LINDNET_MSG_SESSION_DISCONNECT,
} lindnet_msg_e;

typedef struct _lindnet_config_t
{
    int         conv;
    int         mtu;

    // sock cache
    int         sock_sndbuf_size;
    int         sock_rcvbuf_size;

    int         rcv_timeout_ms;

    /*
     * valid for tcp/udp socket
     */
    int         block;

    /*
     * for tcp
     */
    void * user;
    int  (*on_event)(void * user, lindnet_msg_e msg, void * ext1, void * ext2);
} lindnet_config_t;

typedef struct _lindnet_t
{
    void * priv;
    void (*close)(void * thiz);
    int  (*bind)(void * thiz, const char * ip, short port);
    int  (*connect)(void * thiz, const char * ip, short port, int timeout_ms);
    ssize_t (*send)(void * thiz, int sockfd, const uint8_t * data, ssize_t size);
    ssize_t (*recv)(void * thiz, int sockfd, uint8_t * data, ssize_t size);

    int  (*get_sockfd)(void * thiz);
    int  (*get_sockaddr)(void * thiz, char * ip, short * port);

    /*
     * for rdt, get cached buffer count waiting for sending
     */
    int  (*get_waitsend)(void * thiz);
} lindnet_t;

lindnet_t * udp_create(lindnet_config_t * p_config);
lindnet_t * tcp_create(lindnet_config_t * p_config);
lindnet_t * rdt_create(lindnet_config_t * p_config);
lindnet_t * lindnet_create(lindnet_type_e type, lindnet_config_t * p_config);

int set_sock_block(int sockfd, int block);
int set_sock_sndbuf(int sockfd, int size);
int set_sock_rcvbuf(int sockfd, int size);
int set_rcv_timeout(int sockfd, int timeout_ms);
int set_sock_reuse(int sockfd, int flag);
int get_sock_addr(int sockfd, struct sockaddr_in * addr, char * ip, uint16_t * port);
int connect_timeout(int sockfd, struct sockaddr * p_sockaddr, int size, int timeout_ms);
unsigned char ip_2_id(const char * p_ip);
int sock_2_id(int sockfd);

#ifdef __cplusplus
}
#endif

#endif  // __LIND_NETWORK_H__


